﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace ConsoleApp.wayline
{
    public class DjiWaylineHelper
    {
        public const string KML = "kml";
        public const string WMPL = "wpml";
        public const string NAMESPACE_KML = "http://www.opengis.net/kml/2.2";
        public const string NAMESPACE_WMPL = "http://www.dji.com/wpmz/1.0.2";
        public static void generateKmz(WaylineGenerateParams generateParams)
        {
            // 过滤掉 小于0.5m航点
            filterDistanceLt05m(generateParams.point2DS);

            generateKml(generateParams);
            generateWpml(generateParams);

            string srcDirPath = Path.Combine(generateParams.waylineTempDir, generateParams.waylineName);
            string destDirPath = Path.Combine(generateParams.waylineDestDir, generateParams.waylineName + ".kmz");
            if (destDirPath.Contains("/temp"))
            {
                destDirPath = destDirPath.Replace("/temp", "");
            }
            ZipHelper.ZipDirectory(srcDirPath, destDirPath);
        }

        public static void generateKml(WaylineGenerateParams generateParams)
        {
            // 实例化Xml文档对象
            (XmlDocument kmlDoc, XmlNamespaceManager xnsMgr, XmlNode documentNode) = createXmlDocument();
         
            DateTime now = DateTime.Now;
            long nowTimeMillis = GetTimestampMilliseconds(now);
            // 基础信息
            SetFileCreationInfo(kmlDoc, documentNode, nowTimeMillis, nowTimeMillis);
            // 任务信息
            SetMissionConfig(kmlDoc, documentNode, generateParams.missionConfig);
            // 创建航点模板文件夹
            SetWaypointKmlFolder(kmlDoc, documentNode, generateParams.floderParam);

            string destTempDir = Path.Combine(generateParams.waylineDestDir, "temp", generateParams.waylineName, "wpmz");
            if(!Directory.Exists(destTempDir))
            {
                Directory.CreateDirectory(destTempDir);
            }
            string kmlFilePath = Path.Combine(destTempDir, "template.kml");
            // 保存kml文件
            try
            {
                kmlDoc.Save(kmlFilePath);
            }
            catch
            {
                //MessageBox.Show(generateParams.waylineName + ".kml" + "已被打开，请关闭后重试！", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        public static void generateWpml(WaylineGenerateParams generateParams)
        {
            // 实例化Xml文档对象
            (XmlDocument kmlDoc, XmlNamespaceManager xnsMgr, XmlNode documentNode) = createXmlDocument();

            DateTime now = DateTime.Now;
            long nowTimeMillis = GetTimestampMilliseconds(now);
            // 任务信息
            SetMissionConfig(kmlDoc, documentNode, generateParams.missionConfig);
            // 创建航点模板文件夹
            SetWaypointWpmlFolder(kmlDoc, documentNode, generateParams.floderParam);

            string destTempDir = Path.Combine(generateParams.waylineDestDir, "temp", generateParams.waylineName, "wpmz");
            if (!Directory.Exists(destTempDir))
            {
                Directory.CreateDirectory(destTempDir);
            }
            string kmlFilePath = Path.Combine(destTempDir, "waylines.wmpl");
            // 保存kml文件
            try
            {
                kmlDoc.Save(kmlFilePath);
            }
            catch
            {
                //MessageBox.Show(generateParams.waylineName + ".kml" + "已被打开，请关闭后重试！", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        public static void filterDistanceLt05m(List<object> point2ds)
        {
            
        }
        /// <summary>
        /// 创建航点模板文件夹
        /// </summary>
        /// <param name="templateType">模板类型</param>
        /// <param name="templateId">模板ID</param>
        public static XmlNode SetWaypointKmlFolder(XmlDocument xmlDoc, XmlNode documentNode, WaypointFloderParam floderParam)
        {
            XmlElement folderNode = null;
            if(null != xmlDoc && null != documentNode)
            {
                folderNode = AppendChildNode(xmlDoc, documentNode, "Folder", "", "", NAMESPACE_KML);
                // 添加模板信息
                AppendChildNode(xmlDoc, folderNode, "templateType", floderParam.templateType, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, folderNode, "templateId", floderParam.templateId.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, folderNode, "autoFlightSpeed", floderParam.autoFlightSpeed.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, folderNode, "globalHeight", floderParam.globalHeight.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, folderNode, "gimbalPitchMode", floderParam.gimbalPitchMode, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, folderNode, "globalWaypointTurnMode", floderParam.globalWaypointTurnMode, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, folderNode, "globalUseStraightLine", floderParam.globalUseStraightLine.ToString(), "wpml", NAMESPACE_WMPL);

                SetFolderwaylineCoordinateSys(xmlDoc, folderNode, floderParam.waylineCoordinateSysParam);
                SetWaypointHeadingParam(xmlDoc, folderNode, floderParam.globalWaypointHeadingParam, "globalWaypointHeadingParam");

                SetFolderPayloadParam(xmlDoc, folderNode, floderParam.payloadParam);

                SetKmlFolderPlacemarkList(xmlDoc, folderNode, floderParam.placemarks);
            }
            return folderNode;
        }
        public static XmlNode SetWaypointWpmlFolder(XmlDocument xmlDoc, XmlNode documentNode, WaypointFloderParam floderParam)
        {
            XmlElement folderNode = null;
            if (null != xmlDoc && null != documentNode)
            {
                folderNode = AppendChildNode(xmlDoc, documentNode, "Folder", "", "", NAMESPACE_KML);
                // 添加模板信息
                AppendChildNode(xmlDoc, folderNode, "templateId", floderParam.templateId.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, folderNode, "autoFlightSpeed", floderParam.autoFlightSpeed.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, folderNode, "waylineId", floderParam.waylineId.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, folderNode, "executeHeightMode", floderParam.executeHeightMode, "wpml", NAMESPACE_WMPL);

                SetWpmlFolderPlacemarkList(xmlDoc, folderNode, floderParam.placemarks);
            }
            return folderNode;
        }
        /// <summary>
        /// globalWaypointHeadingParam & waypointHeadingParam
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="folderNode"></param>
        /// <param name="waypointHeadingNodeName"> globalWaypointHeadingParam & waypointHeadingParam </param>
        /// <param name="globalWaypointHeadingParam"></param>
        public static void SetKmlFolderPlacemarkList(XmlDocument xmlDoc, XmlNode folderNode, List<Placemark> placemarks)
        {
            if (null != xmlDoc && null != folderNode && null != placemarks && placemarks.Count > 0)
            {
                for(int i = 0; i < placemarks.Count; i++)
                {
                    Placemark placemark = placemarks[i];
                    placemark.index = i;
                    SetKmlFolderPlacemark(xmlDoc, folderNode, placemark);
                }
            }
        }
        public static void SetWpmlFolderPlacemarkList(XmlDocument xmlDoc, XmlNode folderNode, List<Placemark> placemarks)
        {
            if (null != xmlDoc && null != folderNode && null != placemarks && placemarks.Count > 0)
            {
                for (int i = 0; i < placemarks.Count; i++)
                {
                    Placemark placemark = placemarks[i];
                    placemark.index = i;
                    SetWpmlFolderPlacemark(xmlDoc, folderNode, placemark);
                }
            }
        }
        public static void SetKmlFolderPlacemark(XmlDocument xmlDoc, XmlNode folderNode, Placemark placemark)
        {
            if (null != xmlDoc && null != folderNode && null != placemark)
            {
                XmlElement placemarkNode = AppendChildNode(xmlDoc, folderNode, "Placemark", "", "", NAMESPACE_KML);
                XmlElement pointNode = AppendChildNode(xmlDoc, placemarkNode, "Point", "", "", NAMESPACE_KML);
                AppendChildNode(xmlDoc, pointNode, "coordinates", "", "", NAMESPACE_KML);

                AppendChildNode(xmlDoc, placemarkNode, "index", placemark.index.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "useStraightLine", placemark.useStraightLine.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "ellipsoidHeight", placemark.ellipsoidHeight.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "height", placemark.height.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "waypointSpeed", placemark.waypointSpeed.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "useGlobalHeight", placemark.useGlobalHeight.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "useGlobalSpeed", placemark.useGlobalSpeed.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "useGlobalTurnParam", placemark.useGlobalTurnParam.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "gimbalPitchAngle", placemark.gimbalPitchAngle.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "caliFlightEnable", placemark.caliFlightEnable.ToString(), "wpml", NAMESPACE_WMPL);

                SetWaypointHeadingParam(xmlDoc, placemarkNode, placemark.waypointHeadingParam, "waypointHeadingParam");
                SetWaypointTurnParam(xmlDoc, placemarkNode, placemark.waypointTurnParam);

                placemark.actionGroup.actionGroupId = placemark.index;
                placemark.actionGroup.actionGroupStartIndex = placemark.index;
                placemark.actionGroup.actionGroupEndIndex = placemark.index;
                SetActionGroup(xmlDoc, placemarkNode, placemark.actionGroup);
            }
        }

        public static void SetWpmlFolderPlacemark(XmlDocument xmlDoc, XmlNode folderNode, Placemark placemark)
        {
            if (null != xmlDoc && null != folderNode && null != placemark)
            {
                XmlElement placemarkNode = AppendChildNode(xmlDoc, folderNode, "Placemark", "", "", NAMESPACE_KML);
                XmlElement pointNode = AppendChildNode(xmlDoc, placemarkNode, "Point", "", "", NAMESPACE_KML);
                AppendChildNode(xmlDoc, pointNode, "coordinates", "", "", NAMESPACE_KML);

                AppendChildNode(xmlDoc, placemarkNode, "index", placemark.index.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "waypointSpeed", placemark.waypointSpeed.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "executeHeight", placemark.executeHeight.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, placemarkNode, "useStraightLine", placemark.useStraightLine.ToString(), "wpml", NAMESPACE_WMPL);
               
                SetWaypointHeadingParam(xmlDoc, placemarkNode, placemark.waypointHeadingParam, "waypointHeadingParam");
                SetWaypointTurnParam(xmlDoc, placemarkNode, placemark.waypointTurnParam);

                placemark.actionGroup.actionGroupId = placemark.index;
                placemark.actionGroup.actionGroupStartIndex = placemark.index;
                placemark.actionGroup.actionGroupEndIndex = placemark.index;
                SetActionGroup(xmlDoc, placemarkNode, placemark.actionGroup);
            }
        }
        public static void SetActionGroup(XmlDocument xmlDoc, XmlNode parentNode, ActionGroup actionGroup)
        {
            if (null != xmlDoc && null != parentNode && null != actionGroup)
            {
                XmlElement actionGroupNode = AppendChildNode(xmlDoc, parentNode, "actionGroup", "", "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, actionGroupNode, "actionGroupId", actionGroup.actionGroupId.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, actionGroupNode, "actionGroupStartIndex", actionGroup.actionGroupStartIndex.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, actionGroupNode, "actionGroupEndIndex", actionGroup.actionGroupEndIndex.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, actionGroupNode, "actionGroupMode", actionGroup.actionGroupMode, "wpml", NAMESPACE_WMPL);
                
                XmlElement actionTriggerNode = AppendChildNode(xmlDoc, actionGroupNode, "actionTrigger", "", "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, actionTriggerNode, "actionTriggerType", actionGroup.actionTriggerType, "wpml", NAMESPACE_WMPL);

                if(null != actionGroup.actions && actionGroup.actions.Count > 0)
                {
                    for(int i = 0; i < actionGroup.actions.Count; i++)
                    {
                        Action action = actionGroup.actions[i];
                        action.actionId = i;
                        SetActionp(xmlDoc, actionGroupNode, action);
                    }
                }
            }
        }
        public static void SetActionp(XmlDocument xmlDoc, XmlNode parentNode, Action action)
        {
            if (null != xmlDoc && null != parentNode && null != action)
            {
                XmlElement actionNode = AppendChildNode(xmlDoc, parentNode, "action", "", "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, actionNode, "actionId", action.actionId.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, actionNode, "actionActuatorFunc", action.actionActuatorFunc, "wpml", NAMESPACE_WMPL);
                SetActionActuatorFuncParam(xmlDoc, actionNode, action.actionActuatorFuncParams);
            }
        }
        public static void SetActionActuatorFuncParam(XmlDocument xmlDoc, XmlNode parentNode, Dictionary<string, string> actionActuatorFuncParams)
        {
            if (null != xmlDoc && null != parentNode && null != actionActuatorFuncParams && actionActuatorFuncParams.Count > 0)
            {
                XmlElement actionActuatorFuncNode = AppendChildNode(xmlDoc, parentNode, "actionActuatorFuncParam", "", "wpml", NAMESPACE_WMPL);
                foreach(KeyValuePair<string, string> kv in actionActuatorFuncParams)
                {
                    AppendChildNode(xmlDoc, actionActuatorFuncNode, kv.Key, kv.Value, "wpml", NAMESPACE_WMPL);
                }
            }
        }
        public static void SetWaypointTurnParam(XmlDocument xmlDoc, XmlNode parentNode, WaypointTurnParam waypointTurnParam) 
        {
            if (null != xmlDoc && null != parentNode && null != waypointTurnParam)
            {
                XmlElement waypointTurnParamNode = AppendChildNode(xmlDoc, parentNode, "waypointTurnParam", "", "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, waypointTurnParamNode, "waypointTurnMode", waypointTurnParam.waypointTurnMode, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, waypointTurnParamNode, "waypointTurnDampingDist", waypointTurnParam.waypointTurnDampingDist.ToString(), "wpml", NAMESPACE_WMPL);
            }
        }
        /// <summary>
        /// globalWaypointHeadingParam & waypointHeadingParam
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="folderNode"></param>
        /// <param name="waypointHeadingNodeName"> globalWaypointHeadingParam & waypointHeadingParam </param>
        /// <param name="globalWaypointHeadingParam"></param>
        public static void SetFolderPayloadParam(XmlDocument xmlDoc, XmlNode folderNode, PayloadParam payloadParam)
        {
            if (null != xmlDoc && null != folderNode && null != payloadParam)
            {
                XmlElement payloadParamNode = AppendChildNode(xmlDoc, folderNode, "payloadParam", "", "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, payloadParamNode, "payloadPositionIndex", payloadParam.payloadPositionIndex.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, payloadParamNode, "focusMode", payloadParam.focusMode, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, payloadParamNode, "meteringMode", payloadParam.meteringMode, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, payloadParamNode, "returnMode", payloadParam.returnMode, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, payloadParamNode, "samplingRate", payloadParam.samplingRate.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, payloadParamNode, "scanningMode", payloadParam.scanningMode, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, payloadParamNode, "imageFormat", payloadParam.imageFormat, "wpml", NAMESPACE_WMPL);

                AppendChildNode(xmlDoc, payloadParamNode, "dewarpingEnable", payloadParam.dewarpingEnable.ToString(), "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, payloadParamNode, "modelColoringEnable", payloadParam.modelColoringEnable.ToString(), "wpml", NAMESPACE_WMPL);
            }
        }
        /// <summary>
        /// globalWaypointHeadingParam & waypointHeadingParam
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="parentNode"></param>
        /// <param name="waypointHeadingNodeName"> globalWaypointHeadingParam & waypointHeadingParam </param>
        public static void SetWaypointHeadingParam(XmlDocument xmlDoc, XmlNode parentNode, WaypointHeadingParam waypointHeadingParam, string waypointHeadingNodeName = "globalWaypointHeadingParam")
        {
            if (null != xmlDoc && null != parentNode && null != waypointHeadingParam)
            {
                XmlElement waypointHeadingNode = AppendChildNode(xmlDoc, parentNode, waypointHeadingNodeName, "", "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, waypointHeadingNode, "waypointHeadingMode", waypointHeadingParam.waypointHeadingMode, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, waypointHeadingNode, "waypointHeadingAngle", waypointHeadingParam.waypointHeadingAngle.ToString(), "wpml", NAMESPACE_WMPL);    
                AppendChildNode(xmlDoc, waypointHeadingNode, "waypointHeadingPathMode", waypointHeadingParam.waypointHeadingPathMode, "wpml", NAMESPACE_WMPL);
                // AppendChildNode(xmlDoc, waypointHeadingNode, "waypointHeadingAngleEnable", waypointHeadingParam.waypointHeadingAngleEnable.ToString(), "wpml", NAMESPACE_WMPL);
                if(!string.IsNullOrEmpty(waypointHeadingParam.waypointPoiPoint))
                {
                    AppendChildNode(xmlDoc, waypointHeadingNode, "waypointPoiPoint", waypointHeadingParam.waypointPoiPoint, "wpml", NAMESPACE_WMPL);
                }

            }
        }
        public static void SetFolderwaylineCoordinateSys(XmlDocument xmlDoc, XmlNode folderNode, WaylineCoordinateSysParam waylineCoordinateSysParam)
        {
            if(null != xmlDoc && null != folderNode && null != waylineCoordinateSysParam)
            {
                XmlElement wcoordSysParamNode = AppendChildNode(xmlDoc, folderNode, "waylineCoordinateSysParam", "", "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, wcoordSysParamNode, "coordinateMode", waylineCoordinateSysParam.CoordinateMode, "wpml", NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, wcoordSysParamNode, "heightMode", waylineCoordinateSysParam.HeightMode, "wpml", NAMESPACE_WMPL);

                //AppendChildNode(xmlDoc, wcoordSysParamNode, "positioningType", waylineCoordinateSysParam.HeightMode, "wpml", NAMESPACE_WMPL);
                //AppendChildNode(xmlDoc, wcoordSysParamNode, "globalShootHeight", waylineCoordinateSysParam.HeightMode, "wpml", NAMESPACE_WMPL);
                //AppendChildNode(xmlDoc, wcoordSysParamNode, "surfaceFollowModeEnable", waylineCoordinateSysParam.HeightMode, "wpml", NAMESPACE_WMPL);
                //AppendChildNode(xmlDoc, wcoordSysParamNode, "surfaceRelativeHeight", waylineCoordinateSysParam.HeightMode, "wpml", NAMESPACE_WMPL);

            }
        }
        /// <summary>
        /// 任务信息
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="documentNode"></param>
        public static void SetMissionConfig(XmlDocument xmlDoc, XmlNode documentNode, MissionConfigParam config)
        {
            if (null != xmlDoc && null != documentNode)
            {
                // 创建missionConfig节点
                XmlElement missionConfigNode = AppendChildNode(xmlDoc, documentNode, "missionConfig", "", WMPL, NAMESPACE_WMPL);
                if(null != config)
                {
                    // 添加任务配置子节点
                    AppendChildNode(xmlDoc, missionConfigNode, "flyToWaylineMode", config.FlyToWaylineMode, WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, missionConfigNode, "finishAction", config.FinishAction, WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, missionConfigNode, "exitOnRCLost", config.ExitOnRCLost, WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, missionConfigNode, "executeRCLostAction", config.ExecuteRCLostAction, WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, missionConfigNode, "takeOffSecurityHeight", config.TakeOffSecurityHeight.ToString(), WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, missionConfigNode, "globalRTHHeight", config.GlobalRTHHeight.ToString(), WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, missionConfigNode, "globalTransitionalSpeed", config.GlobalTransitionalSpeed.ToString(), WMPL, NAMESPACE_WMPL);

                    if (null != config.TakeOffRefPoint)
                    {
                        AppendChildNode(xmlDoc, missionConfigNode, "takeOffRefPoint", config.TakeOffRefPoint, WMPL, NAMESPACE_WMPL);
                    }
                    if(null != config.TakeOffRefPointAGLHeight)
                    {
                        AppendChildNode(xmlDoc, missionConfigNode, "takeOffRefPointAGLHeight", config.TakeOffRefPointAGLHeight.ToString(), WMPL, NAMESPACE_WMPL);
                    }
                                      
                    // 添加无人机信息
                    XmlElement droneInfo = AppendChildNode(xmlDoc, missionConfigNode, "droneInfo", "", WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, droneInfo, "droneEnumValue", config.DroneEnumValue.ToString(), WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, droneInfo, "droneSubEnumValue", config.DroneSubEnumValue.ToString(), WMPL, NAMESPACE_WMPL);

                    // 添加载荷信息
                    XmlElement payloadInfo = AppendChildNode(xmlDoc, missionConfigNode, "payloadInfo", "", WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, payloadInfo, "payloadEnumValue", config.PayloadEnumValue.ToString(), WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, payloadInfo, "payloadSubEnumValue", config.PayloadSubEnumValue.ToString(), WMPL, NAMESPACE_WMPL);
                    AppendChildNode(xmlDoc, payloadInfo, "payloadPositionIndex", config.PayloadPositionIndex.ToString(), WMPL, NAMESPACE_WMPL);

                }

            }
        }
        /// <summary>
        /// 文件创建信息
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="documentNode"></param>
        /// <param name="createTime"></param>
        /// <param name="updateTime"></param>
        public static void SetFileCreationInfo(XmlDocument xmlDoc, XmlNode documentNode, long? createTime = null, long? updateTime = null)
        {
            if(null != xmlDoc && null != documentNode)
            {
                // 如果未提供时间戳，使用当前时间
                long currentTime = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;
                long createTimestamp = createTime ?? currentTime;
                long updateTimestamp = updateTime ?? currentTime;
                AppendChildNode(xmlDoc, documentNode, "author", "SWSC", WMPL, NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, documentNode, "createTime", createTimestamp.ToString(), WMPL, NAMESPACE_WMPL);
                AppendChildNode(xmlDoc, documentNode, "updateTime", updateTimestamp.ToString(), WMPL, NAMESPACE_WMPL);
            }
        }
        public static (XmlDocument, XmlNamespaceManager, XmlElement) createXmlDocument()
        {
            XmlDocument kmlDoc = new XmlDocument();
            kmlDoc.PreserveWhitespace = false;

            XmlNamespaceManager xnsMgr = new XmlNamespaceManager(kmlDoc.NameTable);
            xnsMgr.AddNamespace(KML, NAMESPACE_KML);
            xnsMgr.AddNamespace(WMPL, NAMESPACE_WMPL);

            // 创建XML声明
            XmlDeclaration xmlDeclaration = kmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
            kmlDoc.AppendChild(xmlDeclaration);

            // 创建根节点
            XmlElement root = AppendChildNode(kmlDoc, null, "kml", "", "", NAMESPACE_KML);
            root.SetAttribute("xmlns:wpml", NAMESPACE_WMPL);

            // 创建Document节点
            XmlElement documentNode = AppendChildNode(kmlDoc, root, "Document", "", "", NAMESPACE_KML);
            return (kmlDoc, xnsMgr, documentNode);
        }

        /// <summary>
        /// 向父节点添加XML子节点（支持命名空间前缀）
        /// </summary>
        /// <param name="doc">XML文档实例</param>
        /// <param name="parent">父节点（根节点的父节点为null）</param>
        /// <param name="childName">子节点本地名称（不能为null或空）</param>
        /// <param name="childValue">子节点文本值（可选）</param>
        /// <param name="prefix">命名空间前缀（如"wpml"，可选）</param>
        /// <param name="namespaceUrl">前缀对应的命名空间URI（当指定prefix时必填）</param>
        /// <returns>创建的子节点</returns>
        /// <exception cref="ArgumentNullException">父节点或节点名为null时抛出</exception>
        /// <exception cref="ArgumentException">节点名为空或前缀与命名空间不匹配时抛出</exception>
        public static XmlElement AppendChildNode(
            XmlDocument doc,
            XmlNode parent,
            string childName,
            string childValue = "",
            string prefix = "",
            string namespaceUrl = ""
        )
        {
            // 校验参数合法性
            if (doc == null) throw new ArgumentNullException(nameof(doc));
            if (string.IsNullOrWhiteSpace(childName))
                throw new ArgumentException("子节点名称不能为空", nameof(childName));
            if (!string.IsNullOrEmpty(prefix) && string.IsNullOrEmpty(namespaceUrl))
                throw new ArgumentException("指定前缀时必须提供命名空间URI", nameof(namespaceUrl));

            // 创建子节点（处理命名空间）
            XmlElement child;
            if (string.IsNullOrEmpty(prefix))
            {
                // 无前缀：使用指定的命名空间或继承父节点的命名空间
                string ns = string.IsNullOrEmpty(namespaceUrl) ?
                    (parent?.NamespaceURI ?? string.Empty) : namespaceUrl;
                child = doc.CreateElement(childName, ns);
            }
            else
            {
                // 有前缀：使用指定的命名空间
                child = doc.CreateElement(prefix, childName, namespaceUrl);
            }

            // 设置节点值
            if (!string.IsNullOrEmpty(childValue))
            {
                child.InnerText = childValue;
            }

            // 添加到父节点（根节点的父节点是文档本身）
            if (parent == null)
            {
                doc.AppendChild(child);
            }
            else
            {
                parent.AppendChild(child);
            }

            return child;
        }

        /// <summary>
        /// 根据 DateTime.Now 获取毫秒级 Unix 时间戳（UTC 基准）
        /// </summary>
        /// <returns>毫秒级时间戳（long 类型，范围：1970-01-01 至今约 2.5e12）</returns>
        public static long GetTimestampMilliseconds(DateTime dateTime)
        {
            // 1. 获取本地时间 -> 转换为 UTC 时间（关键：对齐 Unix 基准时区）
            DateTime utcTime = null != dateTime ? dateTime.ToUniversalTime() : DateTime.Now.ToUniversalTime();

            // 2. 定义 Unix 基准时间（UTC 时区，不可修改）
            DateTime unixBaseTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

            // 3. 计算时间差 -> 转换为总毫秒数
            TimeSpan timeSpan = utcTime - unixBaseTime;
            long timestamp = (long)timeSpan.TotalMilliseconds;

            return timestamp;
        }

        public static Dictionary<string, string> actionActuatorFuncGimbalRotateParams()
        {
            Dictionary<string, string> paramDict = new Dictionary<string, string>();
            paramDict["payloadPositionIndex"] = "0";
            paramDict["gimbalRotateMode"] = "absoluteAngle";
            paramDict["gimbalPitchRotateEnable"] = "1";
            paramDict["gimbalPitchRotateAngle"] = "-90.0";
            paramDict["gimbalRollRotateEnable"] = "0";
            paramDict["gimbalRollRotateAngle"] = "0.0";
            paramDict["gimbalYawRotateEnable"] = "0";
            paramDict["gimbalYawRotateAngle"] = "0.0";
            paramDict["gimbalRotateTimeEnable"] = "0";
            paramDict["gimbalRotateTime"] = "0.0";

            paramDict["gimbalHeadingYawBase"] = "north";
            
            return paramDict;
        }

        public static Dictionary<string, string> actionActuatorFuncZoomParams()
        {
            Dictionary<string, string> paramDict = new Dictionary<string, string>();
            paramDict["payloadPositionIndex"] = "0";
            paramDict["focalLength"] = "48.0";
            paramDict["isUseFocalFactor"] = "0";
            
            return paramDict;
        }

        public static Dictionary<string, string> actionActuatorFuncTakePhotoParams()
        {
            Dictionary<string, string> paramDict = new Dictionary<string, string>();
            paramDict["payloadPositionIndex"] = "0";
            paramDict["useGlobalPayloadLensIndex"] = "1";
            paramDict["payloadLensIndex"] = "zoom,ir";
            paramDict["fileSuffix"] = "01-01-22-007-01,02";

            return paramDict;
        }
    }
}
